// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: support lookup writer/reader proxy info with cmd-tool
// ------------------------------------------------------------------

#ifndef INCLUDE_EDDS_RTPS_WRITER_READERLOCATOR_H_
#define INCLUDE_EDDS_RTPS_WRITER_READERLOCATOR_H_

#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC

#include <vector>
#include <ertps/utils/LocatorAlias.h>
#include <edds/rtps/common/Guid.h>
#include <edds/rtps/common/SequenceNumber.h>
#include <edds/rtps/messages/RTPSMessageGroup.h>
#include <edds/rtps/common/LocatorSelectorEntry.hpp>

namespace evbs {
namespace ertps {
namespace rtps {

class RTPSParticipantImpl;
class RTPSWriter;
class RTPSReader;

/**
 * Class ReaderLocator, contains information about a remote reader, without saving its state.
 * It also implements RTPSMessageSenderInterface, so it can be used when separate sending is
 * enabled.
 * @ingroup WRITER_MODULE
 */
class ReaderLocator : public RTPSMessageSenderInterface {
 public:
    virtual ~ReaderLocator();

    /**
     * Construct a ReaderLocator.
     *
     * @param owner                   Pointer to the RTPSWriter creating this object.
     * @param max_unicast_locators    Maximum number of unicast locators to hold.
     * @param max_multicast_locators  Maximum number of multicast locators to hold.
     */
    ReaderLocator(RTPSWriter* owner, size_t max_unicast_locators, size_t max_multicast_locators);

    bool is_local_reader() const { return is_local_reader_; }

    RTPSReader* local_reader();

    void local_reader(RTPSReader* const local_reader) { local_reader_ = local_reader; }

    const GUID_t& remote_guid() const { return general_locator_info_.remote_guid; }

    LocatorSelectorEntry* general_locator_selector_entry() { return &general_locator_info_; }

    LocatorSelectorEntry* async_locator_selector_entry() { return &async_locator_info_; }

    /**
     * Try to start using this object for a new matched reader.
     *
     * @param remote_guid         GUID of the remote reader.
     * @param unicast_locators    Unicast locators of the remote reader.
     * @param multicast_locators  Multicast locators of the remote reader.
     *
     * @return false when this object was already started, true otherwise.
     */
    bool start(const GUID_t& remote_guid, const ResourceLimitedVector<Locator_t>& unicast_locators,
               const ResourceLimitedVector<Locator_t>& multicast_locators);

    /**
     * Try to update information of this object.
     *
     * @param unicast_locators    Unicast locators of the remote reader.
     * @param multicast_locators  Multicast locators of the remote reader.
     *
     * @return true when information has changed, false otherwise.
     */
    bool update(const ResourceLimitedVector<Locator_t>& unicast_locators,
                const ResourceLimitedVector<Locator_t>& multicast_locators);

    /**
     * Try to stop using this object for an unmatched reader.
     *
     * @param remote_guid  GUID of the remote reader.
     *
     * @return true if this object was started for remote_guid, false otherwise.
     */
    bool stop(const GUID_t& remote_guid);

    /**
     * Try to stop using this object for an unmatched reader.
     */
    void stop();

    /**
     * Check if the destinations managed by this sender interface have changed.
     *
     * @return true if destinations have changed, false otherwise.
     */
    bool destinations_have_changed() const override { return false; }

    /**
     * Get a GUID prefix representing all destinations.
     *
     * @return When all the destinations share the same prefix (i.e. belong to the same participant)
     * that prefix is returned. When there are no destinations, or they belong to different
     * participants, c_GuidPrefix_Unknown is returned.
     */
    GuidPrefix_t destination_guid_prefix() const override { return general_locator_info_.remote_guid.guidPrefix; }

    /**
     * Get the GUID prefix of all the destination participants.
     *
     * @return a const reference to a vector with the GUID prefix of all destination participants.
     */
    const std::vector<GuidPrefix_t>& remote_participants() const override { return guid_prefix_as_vector_; }

    /**
     * Get the GUID of all destinations.
     *
     * @return a const reference to a vector with the GUID of all destinations.
     */
    const std::vector<GUID_t>& remote_guids() const override { return guid_as_vector_; }

    /**
     * Send a message through this interface.
     *
     * @param message Pointer to the buffer with the message already serialized.
     * @param max_blocking_time_point Future timepoint where blocking send should end.
     */
    bool send(CDRMessage_t* message) const override;

    size_t locators_size() const {
        if ((general_locator_info_.remote_guid != c_Guid_Unknown) && (!is_local_reader_)) {
            if (general_locator_info_.unicast.size() > 0U) {
                return general_locator_info_.unicast.size();
            } else {
                return general_locator_info_.multicast.size();
            }
        }

        return 0U;
    }

    /*
     * Do nothing.
     * This object always is protected by writer's mutex.
     */
    void lock() override {}

    /*
     * Do nothing.
     * This object always is protected by writer's mutex.
     */
    void unlock() override {}

    int64_t get_start_time() { return start_time_.to_ns(); }

    bool type_plain() { return m_type_plain; }
    void type_plain(bool plain) { m_type_plain = plain; }

 private:
    RTPSWriter* owner_;
    RTPSParticipantImpl* participant_owner_;
    LocatorSelectorEntry general_locator_info_;
    LocatorSelectorEntry async_locator_info_;
    bool is_local_reader_;
    RTPSReader* local_reader_;
    std::vector<GuidPrefix_t> guid_prefix_as_vector_;
    std::vector<GUID_t> guid_as_vector_;
    Time_t start_time_;

    bool m_type_plain = false;
};

} /* namespace rtps */
} /* namespace ertps */
} /* namespace evbs */

#endif  // ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC
#endif  // INCLUDE_EDDS_RTPS_WRITER_READERLOCATOR_H_
